#ifndef __VECTOR_OPTIMIZED__
#define __VECTOR_OPTIMIZED__

#define VectorPlusVector Sum< Expression<Vector>, Expression<Vector> >
#define ExpressionPlusVector Sum< Expression<A>, Expression<Vector> >
#define VectorPlusExpression Sum< Expression<Vector>, Expression<Vector> >
#define ExpressionPlusExpression Sum< Expression<A>, Expression<B> >
#define ScalarTimesVector Product< Expression<Vector> >
#define ScalarTimesExpression Product< Expression<A> >

template < class T >
class Expression {
	const T expression;
public:
	Expression(const T& t) : expression(t) {}

	float operator[](int i) const
	{
		return expression[i];
	}
};

class Vector{
	float v[3];
public:
	Vector() {}
	Vector(float x_pos, float y_pos, float z_pos)
	{
		v[0] = x_pos;
		v[1] = y_pos;
		v[2] = z_pos;
	}
	float operator[](int i) const
	{
		return v[i];
	}
	float operator[](int i)
	{
		return v[i];
	}

	template <class T>
	Vector(const T& expression)
	{
		v[0] = expression[0];
		v[1] = expression[1];
		v[2] = expression[2];
	}

	template <class T>
	Vector& operator=(const T& expression)
	{
		v[0] = expression[0];
		v[1] = expression[1];
		v[2] = expression[2];
		return *this;
	}
};

template <>
class Expression<Vector> {
	const Vector& V;
public:
	Expression(const Vector& Vc) : V(Vc) {}
	float operator[] (int i) const
	{
		return V[i];
	}
};

template < class LeftT, class RightT >
class Sum {
	const LeftT L;
	const RightT R;
public:
	Sum(const LeftT Linit, const RightT Rinit) : L(Linit), R(Rinit) {}

	float operator[] (int i) const
	{
		return L[i] + R[i];
	}
};

template < class VectorExpressionT >
class Product {
	float scalar;
	const VectorExpressionT V;
public:
	Product( const float s, const VectorExpressionT Vinit) :
	  scalar(s), V(Vinit) {}

	  float operator[](int i) const
	  {
		  return s*V[i];
	  }
};

inline const Expression< VectorPlusVector > operator+( const Vector& a, const Vector& b)
{
	return Expression< VectorPlusVector>  ( VectorPlusVector(a,b) );
}

template< class A > inline const
Expression< ExpressionPlusVector > operator+( const Expression<A> &a, const Vector& b)
{
	return Expression< ExpressionPlusVector > ( ExpressionPlusVector(a,b) );
}

template< class B > inline const
Expression< VectorPlusExpression > operator+(const Vector& a, const Expression<B>& b)
{
	return Expression< VectorPlusExpression > ( VectorPlusExpression(a, b) );
}

template< class A, class B > inline const
Expression< ExpressionPlusExpression > operator+(const Expression<A>& a, const Expression<B>& b)
{
	return Expression< ExpressionPlusExpression >( ExpressionPlusExpression(a, b) );
}

inline const
Expression< ScalarTimesVector> operator* (const  float s, const Vector& V)
{
	return Expression< ScalarTimesVector >( ScalarTimesVector(s, V) );
}

template< class A> inline const
Expression< ScalarTimesExpression > operator* ( const float s, const Expression<A> E)
{
	return Expression< ScalarTimesExpression > ( ScalarTimesExpression(s, E) );
}
#endif